/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.common.utils;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * Collections tools.
 * <p>
 * JDK-Collections, Guava-Collections2, so named Collections3.
 * <p>
 * Created by Peter.Li on 2015/10/9.
 */
public class Collections3 {

    /**
     * Extract the object's attributes in map (by Getter) to build a new Map.
     *
     * @param collection        the source collection.
     * @param keyPropertyName   the key of the new map.
     * @param valuePropertyName the value of the new map.
     */
    public static Map extractToMap(final Collection collection, final String keyPropertyName,
                                   final String valuePropertyName) {
        Map map = new HashMap(collection.size());

        try {
            for (Object obj : collection) {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName),
                        PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw com.intelligent.ispc.common.utils.Reflections.convertReflectionExceptionToUnchecked(e);
        }

        return map;
    }

    /**
     * Extract the object's attributes in map (by Getter) to build a new List.
     *
     * @param collection   the source collection.
     * @param propertyName the attribute name want to be extract.
     */
    public static List extractToList(final Collection collection, final String propertyName) {
        List list = new ArrayList(collection.size());

        try {
            for (Object obj : collection) {
                list.add(PropertyUtils.getProperty(obj, propertyName));
            }
        } catch (Exception e) {
            throw Reflections.convertReflectionExceptionToUnchecked(e);
        }

        return list;
    }

    /**
     * Extract the object's attributes in map (by Getter) to string with separator.
     *
     * @param collection   the source collection.
     * @param propertyName the attribute name want to be extract.
     * @param separator    the separator.
     */
    public static String extractToString(final Collection collection, final String propertyName, final String separator) {
        List list = extractToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    /**
     * Translate all objects in Collection to String (by using toString()), with the separator.
     */
    public static String convertToString(final Collection collection, final String separator) {
        return StringUtils.join(collection, separator);
    }

    /**
     * Translate all objects in Collection to String (by using toString()), with prefix and postfix.
     * like : <div>mymessage</div>.
     */
    public static String convertToString(final Collection collection, final String prefix, final String postfix) {
        StringBuilder builder = new StringBuilder();
        for (Object o : collection) {
            builder.append(prefix).append(o).append(postfix);
        }
        return builder.toString();
    }

    /**
     * Judge whether it's empty.
     */
    public static boolean isEmpty(Collection collection) {
        return (collection == null) || collection.isEmpty();
    }

    /**
     * Judge whether it's empty.
     */
    public static boolean isEmpty(Map map) {
        return (map == null) || map.isEmpty();
    }

    /**
     * Judge whether it's empty.
     */
    public static boolean isNotEmpty(Collection collection) {
        return (collection != null) && !(collection.isEmpty());
    }

    /**
     * Get the first object in Collection, if the collection is empty, return null.
     */
    public static <T> T getFirst(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }

        return collection.iterator().next();
    }

    /**
     * Get the last object in Collection, if the collection is empty, return null.
     */
    public static <T> T getLast(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }

        // when is List，get the last object directly.
        if (collection instanceof List) {
            List<T> list = (List<T>) collection;
            return list.get(list.size() - 1);
        }

        // get the last one by iterator for others class type.
        Iterator<T> iterator = collection.iterator();
        while (true) {
            T current = iterator.next();
            if (!iterator.hasNext()) {
                return current;
            }
        }
    }

    /**
     * return the new List for a+b.
     */
    public static <T> List<T> union(final Collection<T> a, final Collection<T> b) {
        List<T> result = new ArrayList<T>(a);
        result.addAll(b);
        return result;
    }

    /**
     * return the new List for a-b.
     */
    public static <T> List<T> subtract(final Collection<T> a, final Collection<T> b) {
        List<T> list = new ArrayList<T>(a);
        for (T element : b) {
            list.remove(element);
        }

        return list;
    }

    /**
     * return a new List build with the overlap of a and b.
     */
    public static <T> List<T> intersection(Collection<T> a, Collection<T> b) {
        List<T> list = new ArrayList<T>();

        for (T element : a) {
            if (b.contains(element)) {
                list.add(element);
            }
        }
        return list;
    }

    public static Double max(Double[] a) {
        int max = 0;
        for (int i = 0; i < a.length; i++) {
            if(a[i] > a[max]) {
                max = i;
            }
        }

        return a[max];
    }

    public static Double min(Double[] a) {
        int min = 0;
        for (int i = 0; i < a.length; i++) {
            if(a[i] < a[min]) {
                min = i;
            }
        }

        return a[min];
    }
}
